package com.linkoog.devtools.http.raw_index;

import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiMethod;
import com.linkoog.devtools.http.common.HttpMethod;
import com.linkoog.devtools.http.parser.HttpServiceParser;
import com.linkoog.devtools.raw_index.core.PsiMethodRawFileIndex;
import com.linkoog.devtools.type.javadoc.JavaDoc;
import com.linkoog.devtools.type.javadoc.JavaDocParser;
import com.linkoog.devtools.type.swagger.JavaSwaggerParser;
import com.linkoog.devtools.utils.VirtualFileUtils;

import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.Objects;
import java.util.Set;

public class HttpServiceMethodRawFileIndex extends PsiMethodRawFileIndex<HttpServiceMethod> {


    public static final Key<Set<PsiElement>> key = Key.create("DevTools.HttpServiceMethodRawFileIndex.Key");

    public HttpServiceMethodRawFileIndex(Project project) {
    }

    public static HttpServiceMethodRawFileIndex getInstance(Project project){
        return EXTENSION_POINT_NAME.findExtension(HttpServiceMethodRawFileIndex.class, project);
    }

    @Override
    public Key<Set<PsiElement>> getPsiElementKey() {
        return key;
    }

    @Override
    public boolean isLasy() {
        return false;
    }

    @Override
    public boolean support(PsiElement psiElement){
        if (psiElement instanceof PsiMethod psiMethod){
            if (! psiMethod.isValid()) return false;

            final List<HttpServiceParser> extensionList = HttpServiceParser.EXTENSION_POINT_NAME.getExtensionList();
            if (extensionList.isEmpty()) return false;

            for (HttpServiceParser httpServiceParser : extensionList) {
                if (httpServiceParser.support(psiMethod)) return true;
            }
        }
        return false;
    }

    public HttpMethod parseHttpMethod(PsiElement psiElement){
        if (psiElement instanceof PsiMethod psiMethod){
            if (! psiMethod.isValid()) return null;

            final List<HttpServiceParser> extensionList = HttpServiceParser.EXTENSION_POINT_NAME.getExtensionList();
            if (extensionList.isEmpty()) return null;

            for (HttpServiceParser httpServiceParser : extensionList) {
                List<HttpMethod> httpMethods = httpServiceParser.parseHttpMethod(psiMethod);
                if (httpMethods == null || httpMethods.isEmpty()) return null;
                return httpMethods.get(0);
            }
        }
        return null;
    }

    @Override
    public File getCacheFile(Project project) throws IOException {
        return new File(project.getBasePath() + "/.idea/index-data/HttpMethod.idx");
    }

    @Override
    public Class<HttpServiceMethod> getValueClass(Project project) {
        return HttpServiceMethod.class;
    }

    @Override
    public HttpServiceMethod resolve(PsiMethod psiMethod) {
        if (psiMethod == null) return null;
        if (!isInit()) return null;

        PsiClass psiClass = psiMethod.getContainingClass();
        if (psiClass == null || psiClass.getQualifiedName() == null) return null;

        final List<HttpServiceParser> extensionList = HttpServiceParser.EXTENSION_POINT_NAME.getExtensionList();
        if (extensionList.isEmpty()) return null;

        return  extensionList.stream()
                .filter(httpServiceParser -> httpServiceParser.support(psiMethod))
                .map(httpServiceParser -> httpServiceParser.parse(psiMethod))
                .filter(Objects::nonNull)
                .findFirst()
                .map(httpServiceMethod -> {
                    final VirtualFile virtualFile = psiMethod.getContainingFile().getOriginalFile().getVirtualFile();
                    final long timestamp = VirtualFileUtils.getTimestamp(virtualFile);

                    httpServiceMethod.initPsiElement(psiMethod.getProject(), psiMethod);
                    httpServiceMethod.setJavaDocSupplier(() -> JavaDocParser.parse(psiMethod.getDocComment()));
                    httpServiceMethod.setSwaggerCommentSupplier(() -> JavaSwaggerParser.parseMethod(psiMethod));
                    httpServiceMethod.setTimestamp(timestamp);

                    return httpServiceMethod;
                })
                .orElse(null);

    }

}
